using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace UKVSTS
{
    public partial class FieldDefaultValueEditor : Form
    {

        private FieldDefaultValue m_FieldDefaultValue;

        private List<FieldDefaultValue> m_ExcludeFields;

        private WorkItemType m_WIT;

        public FieldDefaultValueEditor()
        {
            InitializeComponent();
        }

        public FieldDefaultValue FieldDefaultValue
        {
            get { return m_FieldDefaultValue; }
        }

        public void SetForEditMode(FieldDefaultValue itemToEdit, WorkItemType wit)
        {
            ArgTest.IsNotNull(itemToEdit);
            ArgTest.IsNotNull(wit);

            m_FieldDefaultValue = itemToEdit;
            m_WIT = wit;

            FieldDefinition fd = m_WIT.FieldDefinitions[m_FieldDefaultValue.FieldName];

            cmbFieldNames.Items.Clear();
            cmbFieldNames.Items.Add(new NamedWrapper<FieldDefinition>(fd, fd.Name));
            cmbFieldNames.SelectedIndex = 0;
        
        }

        public void SetForNewFieldDefaultValueMode(WorkItemType wit, List<FieldDefaultValue> excludeFields)
        {
            ArgTest.IsNotNull(wit);

            m_WIT = wit;
            m_ExcludeFields = excludeFields;
            if (m_ExcludeFields == null)
            {
                m_ExcludeFields = new List<FieldDefaultValue>();
            }

            PopulateFieldNames();
        }

        private void PopulateFieldNames()
        {
            foreach (FieldDefinition fd in m_WIT.FieldDefinitions)
            {
                if (IsFieldSuitableForDefaultValue(fd) && !m_ExcludeFields.Exists(delegate(FieldDefaultValue fdv) { return fd.Name.Equals(fdv.FieldName); }))
                {
                    cmbFieldNames.Items.Add(new NamedWrapper<FieldDefinition>(fd, fd.Name));
                }
            }
        }

        private bool IsFieldSuitableForDefaultValue(FieldDefinition fd)
        {
            return (fd.IsComputed == false || fd.FieldType == FieldType.TreePath) && (fd.IsEditable == true) &&
                   (fd.FieldType == FieldType.Double || fd.FieldType == FieldType.Integer ||
                    fd.FieldType == FieldType.PlainText || fd.FieldType == FieldType.String ||
                    fd.FieldType == FieldType.TreePath);
        }

        private void cmbFieldNames_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtValue.Text = "";
            cmbValue.SelectedIndex = -1;
            lblValidationMessage.Text = "";

            NamedWrapper<FieldDefinition> wrappedFd = cmbFieldNames.SelectedItem as NamedWrapper<FieldDefinition>;
            if (wrappedFd != null)
            {
                lblType.Text = wrappedFd.Item.FieldType.ToString();
                lblHelptext.Text = wrappedFd.Item.HelpText;

                if (wrappedFd.Item.ReferenceName.Equals(CoreFieldReferenceNames.AreaPath) ||
                    wrappedFd.Item.ReferenceName.Equals(CoreFieldReferenceNames.IterationPath))
                {
                    txtValue.BackColor = SystemColors.Control;
                    cmbValue.Visible = false;
                    txtValue.Visible = true;
                    txtValue.ReadOnly = true;
                    txtValue.BackColor = SystemColors.Control;
                    cmdPathSelector.Visible = true;
                    cmdPathSelector.Focus();

                    if (m_FieldDefaultValue != null)
                    {
                        // We are in edit mode, so populate the value
                        txtValue.Text = m_FieldDefaultValue.DefaultValue;
                    }
                }
                else
                {
                    cmdPathSelector.Visible = false;

                    AllowedValuesCollection allowedValues = wrappedFd.Item.AllowedValues;
                    if (allowedValues != null && allowedValues.Count > 0)
                    {
                        cmbValue.Items.Clear();
                        foreach (String value in allowedValues)
                        {
                            cmbValue.Items.Add(value);
                        }

                        cmbValue.Visible = true;
                        txtValue.Visible = false;
                        cmbValue.Focus();

                        if (m_FieldDefaultValue != null)
                        {
                            // We are in edit mode, so populate the value
                            cmbValue.SelectedItem = m_FieldDefaultValue.DefaultValue;
                        }
                    }
                    else
                    {
                        cmbValue.Visible = false;
                        txtValue.Visible = true;
                        txtValue.ReadOnly = false;
                        txtValue.ForeColor = SystemColors.WindowText;
                        txtValue.BackColor = SystemColors.Window;
                        txtValue.Focus();

                        if (m_FieldDefaultValue != null)
                        {
                            // We are in edit mode, so populate the value
                            txtValue.Text = m_FieldDefaultValue.DefaultValue;
                        }
                    }
                }
            }
        }

        private void cmdPathSelector_Click(object sender, EventArgs e)
        {
            NodeCollection nodeCollection = null;
            NamedWrapper<FieldDefinition> wrappedFd = cmbFieldNames.SelectedItem as NamedWrapper<FieldDefinition>;
            if (wrappedFd != null)
            {
                if (wrappedFd.Item.ReferenceName.Equals(CoreFieldReferenceNames.AreaPath))
                {
                    nodeCollection = m_WIT.Project.AreaRootNodes;
                }
                else if (wrappedFd.Item.ReferenceName.Equals(CoreFieldReferenceNames.IterationPath))
                {
                    nodeCollection = m_WIT.Project.IterationRootNodes;
                }
                else
                {
                    MessageBox.Show(this, "Sorry, this field has confused me. I only know how to populate Path fields of Areas and Itterations.",
                                     "IEeee!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }


                if (nodeCollection != null)
                {
                    using (PathSelector dialog = new PathSelector())
                    {
                        dialog.NodeCollection = nodeCollection;
                        if (dialog.ShowDialog() == DialogResult.OK)
                        {
                            txtValue.Text = dialog.GetSelectedNodePath();
                        }
                    }
                }
            }
        }

        private String GetSelectedDefaultValue()
        {
            String txt;
            if (txtValue.Visible)
            {
                txt = txtValue.Text;
            }
            else
            {
                txt = cmbValue.SelectedItem.ToString();
            }
            return txt;
        }

        private void cmdOk_Click(object sender, EventArgs e)
        {
            //m_FieldDefaultValue.DefaultValue = GetSelectedDefaultValue();
        }

        private FieldDefinition SelectedFieldDefinition
        {
            get
            {
                FieldDefinition def = null;
                if (cmbFieldNames.SelectedItem != null)
                {
                    NamedWrapper<FieldDefinition> nw = cmbFieldNames.SelectedItem as NamedWrapper<FieldDefinition>;
                    if (nw != null)
                    {
                        def = nw.Item;
                    }
                }
                return def;
            }
        }

        private bool ValidateValue(String value, out String reason)
        {
            bool valid = false;
            reason = "Unknown";
            FieldDefinition def = SelectedFieldDefinition;
            if (def == null)
            {
                reason = "No field selected";
            }
            else
            {
                switch (def.FieldType)
                {
                    case FieldType.DateTime:
                        valid = ValidateDateTime(value, ref reason);
                        break;

                    case FieldType.Double:
                        valid = ValidateDouble(value, ref reason);
                        break;


                    case FieldType.Integer:
                        valid = ValidateInteger(value, ref reason);
                        break;

                    case FieldType.PlainText:
                    case FieldType.String:
                        valid = true;
                        reason = "ok";
                        break;

                    case FieldType.TreePath:
                        valid = ValidateTreePath(def, value, ref reason);
                        break;

                    case FieldType.History:
                    case FieldType.Html:
                    default:
                        reason = "Unsupported field type";
                        break;
                }

            }
            return valid;
        }

        private static bool ValidateInteger(String value, ref String reason)
        {
            Int32 iParsedValue;
            bool valid = Int32.TryParse(value, out iParsedValue);
            if (valid == false)
            {
                reason = "Invalid integer number format";
            }
            return valid;
        }

        private static bool ValidateDouble(String value, ref String reason)
        {
            Double dParsedValue;
            bool valid = Double.TryParse(value, out dParsedValue);
            if (valid == false)
            {
                reason = "Invalid double number format";
            }
            return valid;
        }

        private static bool ValidateDateTime(String value, ref String reason)
        {
            DateTime dtParsedValue;
            bool valid = DateTime.TryParse(value, out dtParsedValue);
            if (valid == false)
            {
                reason = "Invalid date-time";
            }
            return valid;
        }

        private bool ValidateTreePath(FieldDefinition def, String value, ref String reason)
        {
            bool valid = false;
            NodeCollection nodeColl = null;
            if (def.ReferenceName.Equals(CoreFieldReferenceNames.AreaPath))
            {
                nodeColl = m_WIT.Project.AreaRootNodes;
            }
            else if (def.ReferenceName.Equals(CoreFieldReferenceNames.IterationPath))
            {
                nodeColl = m_WIT.Project.IterationRootNodes;
            }

            if (nodeColl == null)
            {
                reason = "Unknown type of path. I don't know how to validate this value";
            }
            else
            {
                if (PathSelector.NodeFromPath(nodeColl, value) != null)
                {
                    valid = true;
                    reason = "ok";
                }
                else
                {
                    reason = "Invalid Path value.";
                }
            }
            return valid;
        }

        private void txtValue_TextChanged(object sender, EventArgs e)
        {
            if (txtValue.ReadOnly == false)
            {
                String reason;
                if (ValidateValue(txtValue.Text, out reason) == false)
                {
                    txtValue.ForeColor = SystemColors.InfoText;
                    txtValue.BackColor = SystemColors.Info;
                    lblValidationMessage.Text = reason;
                }
                else
                {
                    txtValue.ForeColor = SystemColors.WindowText;
                    txtValue.BackColor = SystemColors.Window;
                    lblValidationMessage.Text = "";
                }
            }
        }

        private void FieldDefaultValueEditor_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (DialogResult == DialogResult.OK)
            {
                String reason;
                if (ValidateValue(txtValue.Text, out reason) == false)
                {
                    MessageBox.Show(this, reason, "Invalid Value", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    e.Cancel = true;
                }
                else
                {
                    if (m_FieldDefaultValue == null)
                    {
                        m_FieldDefaultValue = new FieldDefaultValue(((NamedWrapper<FieldDefinition>)cmbFieldNames.SelectedItem).Item.Name);
                    }
                    m_FieldDefaultValue.DefaultValue = GetSelectedDefaultValue();
                }
            }
        }

        private void FieldDefaultValueEditor_HelpButtonClicked(object sender, CancelEventArgs e)
        {
            e.Cancel = true;
            System.Diagnostics.Process.Start("http://www.codeplex.com/UKVSTS/Wiki/View.aspx?title=Field%20Default%20Value%20Editor");
        }

    }
}